package org.Shiikong_Memory.SakuraBlockFrame.Builder;

import org.Shiikong_Memory.SakuraBlockFrame.Abnormal.NoInitAbnomal;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.plugin.Plugin;

import java.util.*;
import java.util.function.Consumer;

/**
 * 生物构建器类，用于方便地创建和配置 {@link LivingEntity} 实例。
 * 该类采用构建器模式，允许通过链式调用的方式设置生物的各种属性，如名称、生命值、装备等。
 * 同时支持为生物设置死亡事件处理器，在生物死亡时触发相应的逻辑。
 *
 * @author Shiikong_Memory
 * @version 1.0
 */
public class EntityBuilder {
    private static boolean isInit = false;
    private static Plugin plugin;
    private static NamespacedKey key;
    private static final Map<UUID, Consumer<EntityDeathEvent>> CALLBACK_MAP = new HashMap<>();

    private final EntityType entityType;
    private Consumer<EntityDeathEvent> deathHandler;
    private String customName;
    private double health = 20.0;
    private boolean aiEnabled = true;
    private final Map<EquipmentSlot, ItemStack> equipment = new EnumMap<>(EquipmentSlot.class);

    /**
     * 初始化生物构建器。该方法必须在调用 {@link } 方法之前调用，
     * 用于设置插件实例、注册事件监听器和创建命名空间键。
     *
     * @param plugin 插件实例，用于注册事件监听器和创建命名空间键。
     * @param namespacedKeyName 命名空间键的名称，用于在生物的持久化数据容器中存储回调 ID。
     */
    public static void init(Plugin plugin, String namespacedKeyName) {
        EntityBuilder.plugin = plugin;
        plugin.getServer().getPluginManager().registerEvents(new EntityListener(), plugin);
        key = new NamespacedKey(plugin, namespacedKeyName);
        isInit = true;
    }

    /**
     * 创建一个新的 {@link EntityBuilder} 实例。在调用此方法之前，必须先调用 {@link #init(Plugin, String)} 方法。
     *
     * @param type 要构建的生物的类型。
     * @return 一个新的 {@link EntityBuilder} 实例，用于进一步配置生物属性。
     * @throws NoInitAbnomal 如果生物构建器尚未初始化，抛出此异常。
     */
    public static EntityBuilder create(EntityType type) {
        if (!isInit)throw new NoInitAbnomal("生物构建器");
        return new EntityBuilder(type);
    }

    /**
     * 私有构造函数
     * @param type 生物类型
     */
    private EntityBuilder(EntityType type) {
        this.entityType = type;
    }

    /**
     * 设置生物名称
     * @param name 生物名称
     * @return 生物构建器实例
     */
    public EntityBuilder name(String name) {
        this.customName = name;
        return this;
    }

    /**
     * 设置生物生命值
     * @param health 生命值
     * @return 生物构建器实例
     */
    public EntityBuilder health(double health) {
        this.health = Math.max(1, health);
        return this;
    }

    /**
     * 禁用生物AI
     * @return 生物构建器实例
     */
    public EntityBuilder disableAI() {
        this.aiEnabled = false;
        return this;
    }

    /**
     * 设置生物装备
     * @param slot 装备槽位
     * @param item 装备物品
     * @return 生物构建器实例
     */
    public EntityBuilder equipment(EquipmentSlot slot, ItemStack item) {
        this.equipment.put(slot, item);
        return this;
    }

    /**
     * 设置生物死亡事件处理器
     * @param handler 死亡事件处理器
     * @return 生物构建器实例
     */
    public EntityBuilder onDeath(Consumer<EntityDeathEvent> handler) {
        this.deathHandler = handler;
        return this;
    }

    /**
     * 构建生物
     * @param location 生物生成位置
     * @return 生成的生物实例
     */
    public LivingEntity build(org.bukkit.Location location) {
        LivingEntity entity = (LivingEntity) location.getWorld().spawnEntity(location, entityType);

        if (customName != null) {
            entity.setCustomName(customName);
            entity.setCustomNameVisible(true);
        }

        entity.setHealth(health);
        entity.setAI(aiEnabled);

        equipment.forEach((slot, item) ->
                entity.getEquipment().setItem(slot, item)
        );

        if (deathHandler != null && plugin != null) {
            UUID callbackId = UUID.randomUUID();
            PersistentDataContainer pdc = entity.getPersistentDataContainer();
            pdc.set(key, PersistentDataType.STRING, callbackId.toString());
            CALLBACK_MAP.put(callbackId, deathHandler);
        }

        return entity;
    }


    private static class EntityListener implements Listener {
        @EventHandler
        public void onEntityDeath(EntityDeathEvent event) {
            PersistentDataContainer pdc = event.getEntity().getPersistentDataContainer();

            if (pdc.has(key, PersistentDataType.STRING)) {
                UUID entityId = UUID.fromString(pdc.get(key, PersistentDataType.STRING));
                Consumer<EntityDeathEvent> handler = CALLBACK_MAP.get(entityId);
                if (handler != null) {
                    handler.accept(event);
                }
            }
        }
    }

}